package com.guldan.core.response;

/**
 * Created by Silas.
 * Date: 2016/10/1
 * Time: 22:10
 */


//import com.alibaba.dubbo.rpc.RpcException;

import com.guldan.core.exception.BusinessException;
import com.guldan.core.exception.UnexpectedException;
import com.guldan.core.response.JsonObjectMapper;
import com.guldan.core.response.ResponseJsonBean;
import com.guldan.core.search.PagingSearchable;
//import com.dianwoba.middleware.trace.client.TraceUtil;
import com.guldan.core.utils.RequestUtil;
//import com.google.common.base.Strings;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Set;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Order(100)
public class ResponseJsonAspect {
    @Resource
    private MappingJackson2HttpMessageConverter converter;
    @Resource
    private JsonObjectMapper jsonObjectMapper;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final String FAIL_MSG = "操作失败";
    protected static final String reqParamsStringKey = "reqParamsString";

    public ResponseJsonAspect() {
    }

    public void responseBodyPointCut() {
    }

    public void before(JoinPoint jp) throws IOException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.setAttribute("reqStartMsecs", Long.valueOf(System.currentTimeMillis()));
        String uri = request.getRequestURI();
        StringBuilder params = new StringBuilder(uri + " " + request.getMethod() + " with parameters [");
        Enumeration e = request.getParameterNames();

        while (e.hasMoreElements()) {
            String args = (String) e.nextElement();
            params.append(args).append("=").append(request.getParameter(args)).append(",");
        }

        params.append("]");
        request.setAttribute("reqParamsString", params.toString());
        logger.info("reqParamsString " + params.toString());
        Object[] args1 = jp.getArgs();
        this.pagingHandle(args1);
    }

    public void after(Object ret) throws HttpMessageNotWritableException, IOException {
        ResponseJsonBean responseBase = new ResponseJsonBean();
        responseBase.setData(ret);
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
        this.converter.write(responseBase, MediaType.APPLICATION_JSON, outputMessage);
        String returnValue = this.jsonObjectMapper.writeValueAsString(responseBase);
        int len = StringUtils.length(returnValue);
        returnValue = len > 1000 ? StringUtils.substring(returnValue, 0, 1000) + "...}" : returnValue;
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        this.complete(returnValue, request, response);
        this.shutdownResponse(response);
    }

    private void complete(String returnValue, HttpServletRequest request, HttpServletResponse response) {
        long reqStartMsecs = ((Long) request.getAttribute("reqStartMsecs")).longValue();
        String reqParamsString = (String) request.getAttribute("reqParamsString");
        long cost = System.currentTimeMillis() - reqStartMsecs;
        String log = reqParamsString + ",result is " + returnValue + ",cost(ms):" + cost + ",remoteAddr=" + RequestUtil.getNginxRealIp(request);

        if (cost < 2000L) {
            this.logger.info(log);
        } else {
            this.logger.warn(log);
        }

    }

    public void exception(JoinPoint jp, Throwable error) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        ResponseJsonBean responseBase = new ResponseJsonBean();
        responseBase.setStatus(0);
        String reqParamsString = (String) request.getAttribute("reqParamsString");
        String prefix = (StringUtils.isBlank(reqParamsString) ? "" : reqParamsString + ",method ") + jp.getSignature().getName();
        long reqStartMsecs = ((Long) request.getAttribute("reqStartMsecs")).longValue();
        long cost = System.currentTimeMillis() - reqStartMsecs;
        Throwable rootCause = error.getCause();
        if (error instanceof BusinessException || rootCause != null && rootCause instanceof BusinessException) {
            responseBase.setMsg(StringUtils.isBlank(error.getMessage()) ? "操作失败" : error.getMessage());
            BusinessException response1 = (BusinessException) error;
            responseBase.setErrorCode(response1.getErrorCode());
            responseBase.setExtraMsg(response1.getExtraMsg());
        } else if (error instanceof UnexpectedException) {
            responseBase.setMsg("操作失败");
        } /*else if (error instanceof RpcException && error.getCause() instanceof ConstraintViolationException) {
            Set response = ((ConstraintViolationException) error.getCause()).getConstraintViolations();
            if (response != null && response.size() > 0) {
                //this.logger.error(prefix + " validate failed!,cost(ms):" + cost + ",traceId:" + Strings.nullToEmpty(TraceUtil.getTraceId()), error);
                responseBase.setMsg(((ConstraintViolation) response.iterator().next()).getMessage());
            }
        } */ else {
            //this.logger.error(prefix + " occors error,cost(ms):" + cost + ",traceId:" + Strings.nullToEmpty(TraceUtil.getTraceId()), error);
            responseBase.setMsg("操作失败");
        }

        HttpServletResponse response2 = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response2);
        this.converter.write(responseBase, MediaType.APPLICATION_JSON, outputMessage);
        this.complete(String.format("exception:{msg:%s,errorCode:%s}", new Object[]{responseBase.getMsg(), responseBase.getErrorCode()}), request, response2);
        this.shutdownResponse(response2);
    }

    private void shutdownResponse(HttpServletResponse response) throws IOException {
        response.getOutputStream().close();
    }

    private void pagingHandle(Object[] args) {
        if (ArrayUtils.isNotEmpty(args)) {
            Object[] arr$ = args;
            int len$ = args.length;

            for (int i$ = 0; i$ < len$; ++i$) {
                Object arg = arr$[i$];
                if (arg instanceof PagingSearchable) {
                    PagingSearchable pageSearch = (PagingSearchable) arg;
                    if (!pageSearch.isPaging()) {
                        pageSearch.setPerPage(Integer.valueOf(999999));
                    }
                }
            }
        }

    }
}

